package router

import (
	"encoding/binary"
	"gitee.com/sdynasty/clever/clog"
	"gitee.com/sdynasty/clever/sessions"
	"github.com/golang/protobuf/proto"
	"reflect"
)

type ProtoRouter struct {
	pools map[uint16] func(sess *sessions.Session, message proto.Message, cmd uint16)
	pbMap map[uint16] reflect.Type
	noSignInMap map[uint16] bool
}


func NewRouter () *ProtoRouter {
	return &ProtoRouter{
		pools: make(map[uint16] func(sess *sessions.Session, message proto.Message, cmd uint16)),
		pbMap: make(map[uint16] reflect.Type),
		noSignInMap: make(map[uint16] bool),
	}
}

func (this *ProtoRouter) RegisterNoSignIn(cmd uint16, message proto.Message, f func(*sessions.Session, proto.Message, uint16)) {
	this.registerWithSignIn(cmd, message, f, true)
}

func (this *ProtoRouter) Register(cmd uint16, message proto.Message, f func(*sessions.Session, proto.Message, uint16)) {
	this.registerWithSignIn(cmd, message, f, false)
}

// 注册消息
func (this *ProtoRouter) registerWithSignIn(cmd uint16, message proto.Message, f func(*sessions.Session, proto.Message, uint16), noSignIn bool) {
	t := reflect.TypeOf(message)
	clog.LogLogic().Println("register cmd = ", cmd, ", proto = ", t)
	this.pbMap[cmd] = t
	this.pools[cmd] = f
	this.noSignInMap[cmd] = noSignIn
}

func (this *ProtoRouter) HandleMessage (sess *sessions.Session, data []byte) {
	cmd := binary.BigEndian.Uint16(data[:2])
	clog.LogLogic().Printf("Router HandleMessage cmd:%d, len:%d\n", cmd, len(data))

	action, ok_action := this.pools[cmd]
	pbType, ok_pb := this.pbMap[cmd]
	allowNoSignIn, ok_signIn := this.noSignInMap[cmd]

	if ok_action && ok_pb && ok_signIn {
		if !allowNoSignIn && !sess.IsSignIn() {
			clog.LogLogic().Println("未登陆, 拒绝.cmd:", cmd)
			return
		}
		clog.LogLogic().Println("pbType.e = ", pbType.Elem())
		msg := reflect.New(pbType.Elem()).Interface().(proto.Message)

		err := proto.Unmarshal(data[2:], msg)
		if err != nil {
			clog.LogLogic().Println("error:", err)
		} else {
			action(sess, msg, cmd)
		}
	} else {
		clog.LogLogic().Println("can`t find handle for cmd:", cmd)
	}
}
